#include "LineNumberingPushbackReader.h"
namespace clojure_lang {
LineNumberingPushbackReader::LineNumberingPushbackReader(QObject *parent) :
    QIODevice(parent)
{
}

LineNumberingPushbackReader::LineNumberingPushbackReader(QIODevice *base, bool ownership)
{
    _index = 0;
    _columnNumber = 0;
    _lineNumber = 1;
    _atLineStart = true;
    _base = base;
    _ownership = ownership;
}


LineNumberingPushbackReader::~LineNumberingPushbackReader()
{
    if (_ownership) _base->close();
}

qint64 LineNumberingPushbackReader::readData(char *data, qint64 maxlen)
{
    return _base->read(data, maxlen);
}

qint64 LineNumberingPushbackReader::writeData(const char *data, qint64 len)
{
    return _base->write(data, len);
}

int LineNumberingPushbackReader::read()
{
    char data;
    qint64 amount = _base->read(&data, 1);
    int ret = data;

    _prevLineStart = _atLineStart;

    if (amount == 0 )
    {
        _atLineStart = true;
        return -1;
    }
    ++_index;
    _atLineStart = false;
    ++_columnNumber;

    if (ret == '\r')
    {
        _base->peek(&data, 1);
        if ( data == '\n')
        {
            ret = '\n';
            _base->read(&data, 1);
            ++_index;
        }
        else
        {
            noteLineAdvance();
        }

    }

    if (ret == '\n')
        noteLineAdvance();

    return ret;

}

void LineNumberingPushbackReader::noteLineAdvance()
{
    _atLineStart = true;
    _lineNumber ++;
    _prevColumnNumber = _columnNumber -1;
    _columnNumber = 0;

}

void LineNumberingPushbackReader::unread(int chr)
{
    _base->ungetChar((char)chr);
    --_index;
    --_columnNumber;

    if (chr == '\n')
    {
        --_lineNumber;
        _columnNumber = _prevColumnNumber;
        _atLineStart = _prevLineStart;
    }

}

int LineNumberingPushbackReader::index()
{
    return this->_index;
}

int LineNumberingPushbackReader::columnNumber()
{
    return this->_columnNumber;
}

int LineNumberingPushbackReader::lineNumber()
{
    return this->_lineNumber;
}

int LineNumberingPushbackReader::peek()
{
    char d;
    int res = _base->peek(&d, 1);
    return (int)d;
}

bool LineNumberingPushbackReader::atLineStart()
{
    return this->_atLineStart;
}

QString LineNumberingPushbackReader::readLine()
{
    QByteArray ba = QByteArray();
    while (!_base->atEnd())
    {
        int c = read();
        ba.append((char)c);
        if (atLineStart()) {
            return QString();
        }
        if (!_base->atEnd())
        {
            int c2 = read();
            if (atLineStart())
            {
                break;
            }
            unread(c2);
        }

    }
    return QString(ba);
}

}
